package com.pycredit.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.pycredit.bean.CostAnalyzerParam;
import com.pycredit.bean.CostUserAnalyzerParam;
import com.pycredit.bean.ServiceTypePersonCostParam;
import com.pycredit.bean.ServiceTypePersonTimeParam;
import com.pycredit.bean.ServiceTypeSpecialCostParam;
import com.pycredit.exception.BizException;
import com.pycredit.service.IServiceTypeCostAnalyzer;
import com.pycredit.type.ExceptionType;
import com.pycredit.type.ServiceType;
import com.pycredit.util.DateUtil;
import com.pycredit.util.MathUtil;

/**
 * @category 各服务类型成本核算-实现
 * 
 * @author yiz
 * @date 2016年5月24日 下午6:05:27
 * @version 1.0.0 
 * @copyright pycredit.cn 
 */
public class ServiceTypeCostAnalyzer implements IServiceTypeCostAnalyzer {

	/**
	 * @category 得到用户成本列表
	 * @param params
	 * @return
	 * @throws BizException
	 * @throws IllegalAccessException 
	 */
	@Override
	public List<Double> personCostList(List<ServiceTypePersonCostParam> params, int workDay,
			Map<String, Double> personSalary) throws BizException, IllegalAccessException {
		if (null == params || params.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}

		List<Double> results = new ArrayList<Double>();
		for (ServiceTypePersonCostParam param : params) {
			double serviceTypeCost = personCost(workDay, param, personSalary);
			results.add(serviceTypeCost);
		}
		return results;
	}

	/**
	 * @category 得到用户成本列表   服务参数顺序必须为 接口核查（比对）数据量，共享平台数据量，自助核查数据量,批量核查数据量
	 * @param params
	 * @return
	 * @throws BizException
	 * @throws IllegalAccessException 
	 */
	@Override
	public Map<String, Double> personCostByType(List<ServiceTypePersonCostParam> params, int workDay,
			Map<String, Double> personSalary) throws BizException, IllegalAccessException {
		if (null == params || params.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		List<Double> personCostList = personCostList(params, workDay, personSalary);
		Map<String, Double> personCostByType = new HashMap<String, Double>();
		personCostByType.put(ServiceType.JKHC.getKey(), personCostList.get(0));
		personCostByType.put(ServiceType.GXPT.getKey(), personCostList.get(1));
		personCostByType.put(ServiceType.ZZHC.getKey(), personCostList.get(2));
		personCostByType.put(ServiceType.PLHC.getKey(), personCostList.get(3));
		return personCostByType;
	}

	/**
	 * @category 得到用户成本
	 * @param workDay 工作日时间
	 * @param param 各个服务类型人工花费成本
	 * @return
	 * @throws BizException
	 * @throws IllegalAccessException 
	 */
	private double personCost(int workDay, ServiceTypePersonCostParam param, Map<String, Double> personSalary)
			throws BizException, IllegalAccessException {
		//每个服务类型花费的
		List<ServiceTypePersonTimeParam> personTimeParams = param.getPersonTimeParams();
		if (null == personTimeParams || personTimeParams.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		double serviceTypeCost = 0;
		//开始计算
		for (ServiceTypePersonTimeParam timeParam : personTimeParams) {
			int totle = timeParam.getTotleTime();//每个服务，每个人员的工时接口
			double personFee = personSalary.get("person_" + timeParam.getPersonType().getType());
			double currCost = MathUtil.div(MathUtil.mul(totle, personFee), workDay, 4);
			//加法计算
			serviceTypeCost = MathUtil.add(serviceTypeCost, currCost);
		}
		//四舍五入
		BigDecimal bigDecimal = new BigDecimal(serviceTypeCost);
		serviceTypeCost = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return serviceTypeCost;
	}

	/**
	 * @category  专项支出    服务参数顺序必须为 接口核查（比对）数据量，共享平台数据量，自助核查数据量,批量核查数据量
	 * @param serviceTypeSpecialCostParams
	 * @return
	 * @throws BizException
	 */
	@Override
	public Map<String, Double> specialCostByType(List<ServiceTypeSpecialCostParam> serviceTypeSpecialCostParams)
			throws BizException {
		if (serviceTypeSpecialCostParams == null || serviceTypeSpecialCostParams.size() == 0
				|| serviceTypeSpecialCostParams.size() != 4) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		Map<String, Double> specialCostByType = new HashMap<String, Double>();
		specialCostByType.put(ServiceType.JKHC.getKey(), serviceTypeSpecialCostParams.get(0).getTotleCost());
		specialCostByType.put(ServiceType.GXPT.getKey(), serviceTypeSpecialCostParams.get(1).getTotleCost());
		specialCostByType.put(ServiceType.ZZHC.getKey(), serviceTypeSpecialCostParams.get(2).getTotleCost());
		specialCostByType.put(ServiceType.PLHC.getKey(), serviceTypeSpecialCostParams.get(3).getTotleCost());
		return specialCostByType;
	}

	/**
	 * @category 
	 * @param serviceProductNums 产品数量--接口核查（比对）产品数量，共享平台产品数量，自助核查产品数量，批量核查产品数量，
	 * @param personFees 用户成本列表
	 * @return
	 * @throws BizException
	 */
	@Override
	public double personTotleFee(List<Double> serviceProductNums, List<Double> personFees) throws BizException {
		if (null == serviceProductNums || serviceProductNums.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		if (null == personFees || personFees.size() == 0) {
			throw new BizException(ExceptionType.CA_0001.getCode(), ExceptionType.CA_0001.getMsg());
		}
		if (serviceProductNums.size() != personFees.size()) {
			throw new BizException(ExceptionType.CA_0004.getCode(), ExceptionType.CA_0004.getMsg());
		}
		double result = 0;
		for (int i = 0; i < serviceProductNums.size(); i++) {
			result = MathUtil.add(result, serviceProductNums.get(i) * personFees.get(i));
		}
		return result;
	}

	/*	*//**
			* @category 应摊销人员费用合计sum1
			* @param codeCenterTotleFee 2015年代码中心全部人员费用支出a
			* @param personTotleFee 2015年所有产品的人员费用合计b
			* @return
			* @throws BizException
			*//*
			public double personFeeCost(double codeCenterTotleFee, double personTotleFee, CostModelConfig config)
			throws BizException {
			
			double c = config.getC();
			
			double result = personFeeCost(codeCenterTotleFee, personTotleFee, c);
			
			//四舍五入
			BigDecimal bigDecimal = new BigDecimal(result);
			result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
			return result;
			}*/

	/**
	 * @category 日常公用费用核算 sum2：a* aa+ b*bb+c*cc+d*dd+e*ee+f*ff+g*gg+h*hh+i*ii+j*jj+k*kk+l*ll
	 * @return
	 */
	public double dailyFeeCost(List<Double> fees, List<Double> dailyFeeRatio) throws BizException {

		double result = 0;
		if (null == fees || fees.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		if (null == dailyFeeRatio || dailyFeeRatio.size() == 0) {
			throw new BizException(ExceptionType.CA_0001.getCode(), ExceptionType.CA_0001.getMsg());
		}
		if (fees.size() != dailyFeeRatio.size()) {
			throw new BizException(ExceptionType.CA_0004.getCode(), ExceptionType.CA_0004.getMsg());
		}
		for (int i = 0; i < fees.size(); i++) {
			result = MathUtil.add(result, fees.get(i) * dailyFeeRatio.get(i));
		}
		return result;
	}

	/**
	 * @category 运行维护费用核算 sum3：a+b+c+d+e+f；
	 * @param param
	 * @return
	 * @throws BizException 
	 */
	@Override
	public double maintenanceFeeCost(List<Double> fees) throws BizException {
		if (null == fees || fees.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		double result = MathUtil.add(fees);
		return result;
	}

	/**
	 * @category 各服务类型单位运营成本核算 服务参数顺序必须为  接口核查（比对）数据量，共享平台数据量，自助核查数据量,批量核查数据量
	 * @param codeCenterTotleFee
	 * @param personTotleFee 2015年所有产品的人员费用合计b
	 * @param dailyFees 日常公用费用核算参数
	 * @param maintenanceFees 运行维护费用核算参数
	 * @param serviceNums 数据服务量（万条次）
	 * @return
	 * @throws BizException 
	 */
	@Override
	public Map<String, Double> businessServiceCostAvgByType(double codeCenterTotleFee, double personTotleFee,
			List<Double> dailyFees, List<Double> maintenanceFees, List<Double> serviceNums, List<Double> dailyFeeRatio,
			double c) throws BizException {
		//各服务类型单位运营成本核算 返回单位，元
		List<Double> businessServiceCostAvg = businessServiceCostAvg(codeCenterTotleFee, personTotleFee, dailyFees,
				maintenanceFees, serviceNums, dailyFeeRatio, c);

		if (businessServiceCostAvg == null || businessServiceCostAvg.size() == 0
				|| businessServiceCostAvg.size() != 4) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		Map<String, Double> businessServiceCostAvgByType = new HashMap<String, Double>();
		businessServiceCostAvgByType.put(ServiceType.JKHC.getKey(), businessServiceCostAvg.get(0));
		businessServiceCostAvgByType.put(ServiceType.GXPT.getKey(), businessServiceCostAvg.get(1));
		businessServiceCostAvgByType.put(ServiceType.ZZHC.getKey(), businessServiceCostAvg.get(2));
		businessServiceCostAvgByType.put(ServiceType.PLHC.getKey(), businessServiceCostAvg.get(3));

		return businessServiceCostAvgByType;
	}

	/**
	 * @category 产品基础成本（1个单位）
	 * @param unitCost 单位运营成本（接口核查等）
	 * @param riskCoeff 风险系数
	 * @return
	 * @throws BizException
	 */
	@Override
	public double baseCost(double unitCost, double riskCoeff) throws BizException {
		double result = MathUtil.mul(MathUtil.mul(unitCost, 10), riskCoeff);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 查询类型
	 * @param searchTypes
	 * @return
	 * @throws BizException 
	 */
	private double calcSerchTypeAdd(String searchTypes, List<String[]> values) throws BizException {
		double searchTypeResult = 0;
		if (StringUtils.isBlank(searchTypes)) {
			throw new BizException("输入的查询类型参数异常，请确认参数书否正常！");
		} else {
			String[] searchTypeArr = searchTypes.split("、");
			for (String searchType : searchTypeArr) {
				double searchTypeVal = getXValueByStr(searchType, "C6", values);
				searchTypeResult = MathUtil.add(searchTypeResult, searchTypeVal);
			}
		}
		BigDecimal bigDecimal = new BigDecimal(searchTypeResult);
		searchTypeResult = bigDecimal.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
		return searchTypeResult;
	}

	/**
	 * @category 转换
	 * @param corpType
	 * @return
	 */
	private String excCorpType(String corpType) {
		if ("央企".equals(corpType) || "国有".equals(corpType) || "事业单位".equals(corpType)) {
			return "国有";
		} else if ("民企".equals(corpType)) {
			return "民企";
		} else if ("混合".equals(corpType) || "其他".equals(corpType)) {
			return "混合";
		}
		return "";
	}

	/**
	 * @category 计算权重
	 * @return
	 * @throws BizException 
	 * @throws IllegalAccessException 
	 */
	@Override
	public double calcWeight(CostUserAnalyzerParam costUserAnalyzerParam, List<List<String[]>> userWeightList)
			throws BizException, IllegalAccessException {
		int year = DateUtil.getYearInterval(costUserAnalyzerParam.getOpenDate(), new Date());
		//注册资金
		double registFund = getXValueByNumber(costUserAnalyzerParam.getRegistFund() + "", "C1", userWeightList.get(0));
		//行业排名:权威，领先，较好，中等，一般
		double tradeRank = getXValueByStr(costUserAnalyzerParam.getTradeRank(), "C2", userWeightList.get(1));
		//计划查询量:大,中,小,极小
		double searchCount = getXValueByStr(costUserAnalyzerParam.getSearchCount(), "C3", userWeightList.get(2));
		//主要查询用途:信用报告基础信息,身份核查,其它
		double searchReason = getXValueByStr(costUserAnalyzerParam.getSearchReason(), "C4", userWeightList.get(3));
		//单位性质:国有,民企,混合
		//转换
		String corpTypeStr = excCorpType(costUserAnalyzerParam.getCorpType());
		double corpType = getXValueByStr(corpTypeStr, "C5", userWeightList.get(4));
		//查询类型:接口,批量,其他,自助核查
		double searchType = calcSerchTypeAdd(costUserAnalyzerParam.getSearchTypes(), userWeightList.get(5));
		//开业时间
		double openDate = getXValueByNumber(year + "", "C7", userWeightList.get(6));
		//员工数量
		double employeeCount = getXValueByNumber(costUserAnalyzerParam.getEmployeeCount() + "", "C8",
				userWeightList.get(7));

		double result = MathUtil.add(registFund, tradeRank, searchCount, searchReason, corpType, searchType, openDate,
				employeeCount);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 用户风险评分=(a-0.3317)/0.4484*100=98
	 * @param weight 权重
	 * @return
	 * @throws BizException 
	 */
	@Override
	public double calcUserRiseGrade(double weight) throws BizException {
		double result = 0;
		try {
			result = MathUtil.mul(MathUtil.div(MathUtil.sub(weight, 0.3317), 0.4484, 4), 100);
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}
		return result;
	}

	/**
	 * @category 用户风险系数=(100（1+R） R^(-1)-用户风险评分)/(100R^(-1) )
	 * @param userRiseGrade 用户风险评分
	 * @param r 配置文件 可以调整的参数，默认为0.5
	 * @return
	 * @throws BizException 
	 * @throws IllegalAccessException
	 */
	@Override
	public double calcUserRiseCoeff(double userRiseGrade, double r) throws BizException {
		//Math.pow
		double result = MathUtil.add(1, r);
		result = MathUtil.mul(100.0, result);
		result = MathUtil.mul(result, Math.pow(r, -1));
		result = MathUtil.sub(result, userRiseGrade);
		try {
			result = MathUtil.div(result, MathUtil.mul(100.0, Math.pow(r, -1)), 4);
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}
		return result;
	}

	/**
	 * @category 人工比对（核查）成本=10000/350*批量A类人员费用/245
	 * @param dailyDeal 每日处理条数，配置为文件
	 * @param batchFee 批量A类人员费用
	 * @return
	 * @throws BizException
	 */
	@Override
	public double artificialCost(double dailyDeal, double batchFee, double workDay) throws BizException {
		if (dailyDeal <= 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		double result = 0;
		try {
			result = MathUtil.div(10000.0, dailyDeal, 5);
			result = MathUtil.mul(result, batchFee);
			result = MathUtil.div(result, workDay, 5);
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}
		return result;
	}

	/**
	 * @category  一般变动成本=  单位运营成本 * 产品单位 * 数据量（万条） *字段成本系数 
	 * @param unitOperatingCosts 单位运营成本
	 * @param productNum 产品单位
	 * @param dataNum 数据量（万条）
	 * @param filedType 字段成本系数
	 * @return 一般变动成本
	 */
	@Override
	public double generalChangeCost(double unitOperatingCost, int productNum, double dataNum, double filedVal) {
		double result = MathUtil.mul(unitOperatingCost, productNum);
		result = MathUtil.mul(result, dataNum);
		result = MathUtil.mul(result, filedVal);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 项目变动成本 = （项目人工成本 + 项目专项支出)* 字段成本系数
	 * @param personCost 项目人工成本
	 * @param specialCost 项目专项支出
	 * @param filedVal 字段成本系数
	 * @return
	 */
	@Override
	public double projectChangeCost(double personCost, double specialCost, double filedVal) {
		double result = MathUtil.mul(MathUtil.add(personCost, specialCost), filedVal);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 产品变动成本 = （一般变动成本+项目变动成本*分摊系数） *风险系数 ,机器处理成本
	 * @param generalChangeCost 一般变动成本
	 * @param projectChangeCost 项目变动成本
	 * @param sharingcoeff 分摊系数
	 * @param userRiskcoeff 用户风险系数 
	 * @param riskcoeff 风险控制成本系数
	 * @return
	 */
	@Override
	public double productChangeCost(double generalChangeCost, double projectChangeCost, double sharingcoeff,
			double riskcoeff) {
		double result = MathUtil.mul(MathUtil.add(generalChangeCost, MathUtil.mul(projectChangeCost, sharingcoeff)),
				riskcoeff);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 批量核查人工处理成本=数据量*查询质量*人工比对（核查）成本
	 * @param dataNum 数据量
	 * @param quality 查询质量
	 * @param personCompareCost 人工比对（核查）成本
	 * @return
	 */
	@Override
	public double personDealCost(double dataNum, double quality, double personCompareCost) {
		double result = MathUtil.mul(dataNum, MathUtil.sub(1.0, quality));
		result = MathUtil.mul(result, personCompareCost);
		return result;
	}

	/**
	 * @category 产品成本 = 产品基础成本 + 产品变动成本
	 * @param baseProductCost 产品基础成本
	 * @param productChangeCost 产品变动成本
	 * @return
	 */
	@Override
	public double productCost(double baseProductCost, double productChangeCost) {
		double result = MathUtil.add(baseProductCost, productChangeCost);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 产品成本=人工处理成本 +机器处理成本
	 * @param personDealCost 批量核查人工处理成本
	 * @param productChangeCost 机器处理成本
	 * @return
	 */
	@Override
	public double productCostBatch(double personDealCost, double productChangeCost) {
		double result = MathUtil.add(personDealCost, productChangeCost);
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 客户项目价格 = 产品成本 * 利润附加比例 * 用户风险系数
	 * @param productCost 产品成本
	 * @param profitRatio 利润附加比例 
	 * @param userRiskcoeff 用户风险系数
	 * @return
	 */
	@Override
	public double customProductPrice(double productCost, double profitRatio, double userRiskcoeff) {
		double result = MathUtil.mul(productCost, MathUtil.add(1, profitRatio));
		result = MathUtil.mul(result, userRiskcoeff);
		return result;
	}

	/**
	 * @category 得到最后计算的参数列表
	 * @param costAnalyzerParams
	 * @return
	 * @throws BizException 
	 */
	@Override
	public List<CostAnalyzerParam> getLastCostAnalyzerParam(List<CostAnalyzerParam> costAnalyzerParams)
			throws BizException {
		Map<String, Integer> projectMap = new HashMap<String, Integer>();
		//总数据量，非批量查询
		double totleDataNum = 0;
		//总数据量，批量查询
		double totleDataNumBat = 0;
		//找出相同的大类，当为非批量处理时，之后需要将处理量减少10W
		for (CostAnalyzerParam costAnalyzerParam : costAnalyzerParams) {
			double dataNum = costAnalyzerParam.getDataNum();
			if (dataNum < 10) {
				dataNum = 10;
				costAnalyzerParam.setDataNum(dataNum);
			}
			String project = costAnalyzerParam.getServiceChildType().getServiceType().getKey();
			if (ServiceType.PLHC.getKey().equals(project)) {
				totleDataNumBat = MathUtil.add(totleDataNumBat, dataNum);
			} else {
				totleDataNum = MathUtil.add(totleDataNum, dataNum);
			}
			Integer getExistVal = existKeyMap(projectMap, project);
			projectMap.put(project, getExistVal + 1);
		}
		//计算分摊系数
		try {
			for (CostAnalyzerParam costAnalyzerParam : costAnalyzerParams) {
				double dataNum = costAnalyzerParam.getDataNum();
				String project = costAnalyzerParam.getServiceChildType().getServiceType().getKey();
				if (ServiceType.PLHC.getKey().equals(project)) {
					costAnalyzerParam.setSharingcoeff(MathUtil.div(dataNum, totleDataNumBat, 6));
				} else {
					costAnalyzerParam.setSharingcoeff(MathUtil.div(dataNum, totleDataNum, 6));
					//由于产品基础成本中已经包含10万条数据量的成本,此处需要减10
					costAnalyzerParam.setDataNum(MathUtil.sub(dataNum, 10));
				}
			}
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}
		return costAnalyzerParams;
	}

	/**
	 * @category 返回键值数量
	 * @param projectMap
	 * @param key
	 * @return
	 */
	private Integer existKeyMap(Map<String, Integer> projectMap, String key) {
		if (projectMap.containsKey(key)) {
			return projectMap.get(key);
		} else {
			return 0;
		}
	}

	/**
	 * @category 获取配置中的值 数字形式
	 */
	private double getXValueByNumber(String value, String type, List<String[]> values) throws BizException {
		if (StringUtils.isBlank(value)) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		int index = -1;
		double result = 0;
		// 根据value 计算落在values 的哪个区间
		if ("C1".equals(type) || "C7".equals(type) || "C8".equals(type)) {
			String[] thisKeyArr = new String[values.size()];
			String[] thisWeightArr = new String[values.size()];
			for (int i = 0; i < values.size(); i++) {
				thisKeyArr[i] = values.get(i)[0];
				thisWeightArr[i] = values.get(i)[1];
			}

			for (int i = 0; i < thisKeyArr.length; i++) {
				if (i < thisKeyArr.length - 1 && Double.parseDouble(value) > Double.parseDouble(thisKeyArr[i])
						&& Double.parseDouble(value) <= Double.parseDouble(thisKeyArr[i + 1])) {
					index = i;
					break;
				} else if (i == thisKeyArr.length - 1
						&& Double.parseDouble(value) > Double.parseDouble(thisKeyArr[i])) {
					index = i;
					break;
				}
			}
			if (index == -1) {
				throw new BizException(ExceptionType.CA_0001.getCode(),
						"输入参数错误， 类型：<" + type + ">, 值: <" + value + ">.");
			}
			result = Double.valueOf(thisWeightArr[index]);
		}
		if (index == -1) {
			throw new BizException(ExceptionType.CA_0001.getCode(),
					"输入参数错误，没有找到相应的配置! 类型：<" + type + ">, 值: <" + value + ">.");
		}
		return result;
	}

	/**
	 * @category 获取配置中的值，字符串形式
	 */
	private double getXValueByStr(String value, String type, List<String[]> values) throws BizException {
		if (StringUtils.isBlank(value)) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg() + "请确认参数是否不为空！");
		}
		int index = -1;
		String[] thisKeyArr = new String[values.size()];
		String[] thisWeightArr = new String[values.size()];
		for (int i = 0; i < values.size(); i++) {
			thisKeyArr[i] = values.get(i)[0];
			thisWeightArr[i] = values.get(i)[1];
		}
		for (int i = 0; i < thisKeyArr.length; i++) {
			if (thisKeyArr[i].trim().equals(value.trim())) {
				index = i;
				break;
			}
		}
		if (index == -1 && ("C5".equals(type) || "C7".equals(type))) {
			index = thisKeyArr.length - 1;
		}
		if (index == -1) {
			throw new BizException(ExceptionType.CA_0001.getCode(),
					"输入参数错误，没有找到相应的配置! 类型：<" + type + ">, 值: <" + value + ">.");
		}

		return Double.valueOf(thisWeightArr[index]);
	}

	/**
	 * @category 总应摊销金额sum=sum1+sum2+sum3
	 * @param personFeeCost 应摊销人员费用合计
	 * @param dailyFeeCost 日常公用费用核算
	 * @param maintenanceFeeCost 运行维护费用核算
	 * @return
	 */
	private double totleCostFee(double personFeeCost, double dailyFeeCost, double maintenanceFeeCost) {
		double result = MathUtil.add(personFeeCost, dailyFeeCost, maintenanceFeeCost);
		return result;
	}

	/**
	 * @category 应摊销人员费用合计sum1：(a-b)*c
	 * @param codeCenterTotleFee 2015年代码中心全部人员费用支出a
	 * @param personFee 2015年所有产品的人员费用合计b
	 * @param c 可配置参数且0=<c<=1，初始设置为0.25
	 * @return
	 * @throws BizException
	 */
	private double personFeeCost(double codeCenterTotleFee, double personTotleFee, double c) throws BizException {
		if (c < 0 || c > 1) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		double result = MathUtil.sub(codeCenterTotleFee, personTotleFee);
		result = MathUtil.mul(result, c);
		//四舍五入
		BigDecimal bigDecimal = new BigDecimal(result);
		result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		return result;
	}

	/**
	 * @category 各服务类型单位运营成本核算 返回单位，元
	 * @param codeCenterTotleFee 代码中心全部人员费用支出参数
	 * @param personTotleFee  所有产品的人员费用参数 此值需要计算
	 * @param dailyFees  日常公用费用核算参数
	 * @param maintenanceFees 运行维护费用核算参数
	 * @param serviceNums 数据服务量（万条次）
	 * @return
	 * @throws BizException
	 */
	private List<Double> businessServiceCostAvg(double codeCenterTotleFee, double personTotleFee,
			List<Double> dailyFees, List<Double> maintenanceFees, List<Double> serviceNums, List<Double> dailyFeeRatio,
			double c) throws BizException {
		if (null == serviceNums || serviceNums.size() == 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(), ExceptionType.CA_0003.getMsg());
		}
		double personFeeCost = personFeeCost(codeCenterTotleFee, personTotleFee, c);//342.42
		double dailyFeeCost = dailyFeeCost(dailyFees, dailyFeeRatio);//147.72
		double maintenanceFeeCost = maintenanceFeeCost(maintenanceFees);//459.6
		double totleCostFee = totleCostFee(personFeeCost, dailyFeeCost, maintenanceFeeCost);//949.74
		//总服务数量
		double totleServiceNum = 0;//2020.0
		//各个服务的数量
		for (Double serviceNum : serviceNums) {
			totleServiceNum = MathUtil.add(totleServiceNum, serviceNum);
		}
		List<Double> results = new ArrayList<Double>();
		try {
			for (Double serviceNum : serviceNums) {

				double currFee = MathUtil.div(MathUtil.mul(totleCostFee, serviceNum), totleServiceNum, 6);//611.21

				double result = MathUtil.mul(MathUtil.div(currFee, serviceNum, 6), 10000);
				//四舍五入
				BigDecimal bigDecimal = new BigDecimal(result);
				result = bigDecimal.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
				results.add(result);
			}
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}
		return results;
	}
}
